From 249e385031f2857e82c07d55cd7eb2ad9b5f3947 Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Fri, 20 Jun 2014 16:03:12 +0100
Subject: [PATCH] dwc_otg: Fix various issues with root port and transaction
 errors

Process the host port interrupts correctly (and don't trample them).
Root port hotplug now functional again.

Fix a few thinkos with the transaction error passthrough for fiq_fsm.
---
 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 7 +++----
 drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c  | 6 +++++-
 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2 +-
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
index 065807f..96c76e3 100644
--- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
@@ -1348,10 +1348,9 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gin
 		local_fiq_disable();
 		/* Pull in the interrupts that the FIQ has masked */
 		gintmsk.d32 |= ~(hcd->fiq_state->gintmsk_saved.d32);
+		gintmsk.d32 |= gintmsk_common.d32;
 		/* for the upstairs function to reenable - have to read it here in case FIQ triggers again */
-		reenable_gintmsk->d32 |= gintmsk.d32;
-		reenable_gintmsk->d32 |= ~(hcd->fiq_state->gintmsk_saved.d32);
-		reenable_gintmsk->d32 &= gintmsk_common.d32;
+		reenable_gintmsk->d32 = gintmsk.d32;
 		local_fiq_enable();
 	}
 
@@ -1535,7 +1534,7 @@ int32_t dwc_otg_handle_common_intr(void *dev)
 //		fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "CILOUT %1d", retval);
 //		fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintsts.d32);
 //		fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintmsk_reenable.d32);
-		if (retval) {
+		if (retval && fiq_enable) {
 			DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_reenable.d32);
 		}
 
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
index 7aad7f7..f9d65e7 100644
--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
@@ -696,7 +696,11 @@ static int notrace noinline fiq_fsm_do_hcintr(struct fiq_state *state, int num_c
 		fiq_print(FIQDBG_ERR, state, "ERRST %02d", n);
 		if (hcint_probe.b.nak || hcint_probe.b.ack || hcint_probe.b.datatglerr) {
 			fiq_print(FIQDBG_ERR, state, "RESET %02d", n);
-			st->nr_errors = 0;
+			/* In some random cases we can get a NAK interrupt coincident with a Xacterr
+			 * interrupt, after the device has disappeared.
+			 */
+			if (!hcint.b.xacterr)
+				st->nr_errors = 0;
 			hcintmsk.b.nak = 0;
 			hcintmsk.b.ack = 0;
 			hcintmsk.b.datatglerr = 0;
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
index d3e2035..6182d3e 100644
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
@@ -2619,7 +2619,7 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
 			case FIQ_PASSTHROUGH_ERRORSTATE:
 				/* Hook into the error count */
 				fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "HCDERR%02d", num);
-				if (dwc_otg_hcd->fiq_state->channel[num].nr_errors) {
+				if (!dwc_otg_hcd->fiq_state->channel[num].nr_errors) {
 					qtd->error_count = 0;
 					fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET   ");
 				}
-- 
1.9.3

